package gu.simplemq.stomp;

import static com.google.common.base.Preconditions.checkNotNull;

import java.net.URISyntaxException;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeoutException;

import javax.net.ssl.SSLException;

import org.projectodd.stilts.stomp.DefaultHeaders;
import org.projectodd.stilts.stomp.StompException;
import org.projectodd.stilts.stomp.client.StompClient;

import gu.simplemq.pool.BaseMQPool;
import gu.simplemq.utils.IntrospectionSupport;
/**
 * 延迟初始化的 {@link StompClient} 资源池(线程安全)<br>
 * @author guyadong
 *
 */
public class StompPoolLazy extends BaseMQPool<StompClient> implements StompConstants{
	private static final String CLIENT_ID_PREFIX = "stilts";
	private String serverURI;
	private long timeoutMills = 0;
	@SuppressWarnings("serial")
	private final DefaultHeaders headers = new DefaultHeaders(){
		{/** 设置默认client id */put(STOMP_clientId, generateClientId());}
	};
	private volatile StompClient stompClient;

	/**
	 * 构造方法，用于{@link gu.simplemq.pool.NamedMQPools#createPool(Properties)}反射调用创建实例
	 * 
	 * @param props
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public StompPoolLazy (Properties props) {
		super(PropertiesHelper.SHELPER.initParameters(props), PropertiesHelper.SHELPER.getLocationlURI(props));
		IntrospectionSupport.setProperties(this, properties, false);
		Map m = IntrospectionSupport.extractProperties(properties, HEADER_PREFIX);
		headers.putAll(m);
	}
	
	public StompPoolLazy setServerURI(String serverURI) {
		this.serverURI = serverURI;
		return this;
	}

	public StompPoolLazy setClientId(String clientId) {
		headers.put(STOMP_clientId, checkNotNull(clientId,"clientId is null"));
		return this;
	}

	public StompPoolLazy setTimeoutMills(long timeoutMills) {
		this.timeoutMills = timeoutMills;
		return this;
	}

	/**
	 * @see gu.simplemq.pool.BaseMQPool#borrow()
	 * @throws MQPoolException 
	 */
	@Override
	public StompClient borrow()throws MQPoolException{
		// double-checked locking
		if(stompClient == null){
			synchronized (this) {
				if(stompClient == null){
			        try {
			        	// 设置是否显示异常
			        	// DebugHandler.setTrace(true);
			    		stompClient = new StompClient(serverURI);
			    		if(timeoutMills > 0){
			    			stompClient.connect(timeoutMills);
			    		}else{
			    			stompClient.connect();
			    		}
			    		logger.info("stomp client initialized(STOMP客户端初始化)  {} ", getCanonicalURI());
					} catch (URISyntaxException | SSLException | InterruptedException | TimeoutException | StompException e) {
						throw new MQPoolException(e);
					}
				}
			}
		}
    	return stompClient;
    }
    
	@Override
    public void release(StompClient r) {
		// DO NOTHING
    }
	@Override
	public void close(){
		// double check
		if(stompClient != null){
			synchronized (this) {
				if(stompClient != null){
					try {
						stompClient.disconnect();
						logger.info("discard stomp client: {}",this);
						stompClient = null;
						closed = true;
					} catch (Throwable e) {
						throw new MQPoolException(e);
					}
				}				
			}
		}
	}
	
	public DefaultHeaders getHeaders() {
		return headers;
	}
	/**
	 * Returns a randomly generated client identifier based on the the fixed
	 * prefix (stilts) and the system time.
	 * <p>
	 * @return a generated client identifier
	 */
	public static String generateClientId() {
		// length of nanoTime = 15, so total length = 19 < 65535(defined in
		// spec)
		return CLIENT_ID_PREFIX + System.nanoTime();

	}
}
